/*
 *  Copyright (C) 2009-2011 Texas Instruments, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _SOSAL_UINPUT_H_
#define _SOSAL_UINPUT_H_

/*! \file
 * \brief The SOSAL User Input API.
 * \author Erik Rainey <erik.rainey@ti.com>
 */

#include <sosal/types.h>

#define _UINPUT_T_FUNCS
#define _UINPUT_FEATURE

#if defined(PLAYBOOK)
// Pegasus touch panel is fixed to 1280x768
#define UINPUT_MAX_TOUCH_X  (SCREEN_DIM_X + 200) // 1280
#define UINPUT_MAX_TOUCH_Y  (SCREEN_DIM_Y + 48)  // 768
#elif defined(BLAZE) || defined(SDP) || defined(BLAZE_TABLET)
// These duplicate a Synaptics Touchpad on Blaze
#define UINPUT_MAX_TOUCH_X  (SCREEN_DIM_X * 4)  // ~3411 on Blaze
#define UINPUT_MAX_TOUCH_Y  (SCREEN_DIM_Y * 4)  // ~1918 on Blaze
#elif defined(SYSBIOS)
#undef _UINPUT_FEATURE
#undef _UINPUT_T_FUNCS
#else
#ifndef SCREEN_DIM_X
#undef _UINPUT_FEATURE
#undef _UINPUT_T_FUNCS
#endif
#define UINPUT_MAX_TOUCH_X  (SCREEN_DIM_X)
#define UINPUT_MAX_TOUCH_Y  (SCREEN_DIM_Y)
#endif

/*! \brief A generic key code.
 * \ingroup group_uinput
 */
typedef uint16_t code_t;

/*! \brief A generic key press state.
 * \ingroup group_uinput
 */
typedef enum _input_key_state_e {
    INPUT_KEY_STATE_UP = 0,     /*!< \brief The key has been let go. */
    INPUT_KEY_STATE_DOWN,       /*!< \brief The key has been pressed. */
    INPUT_KEY_STATE_REPEAT      /*!< \brief The key is repeating */
} input_key_state_e;

/*! \brief A generic key operation. 
 * \ingroup group_uinput
 */
typedef struct _input_key_t {
    code_t             code;    /*!< \brief The key code */
    input_key_state_e state;  /*!< \brief the key state. */
} input_key_t;

/*! \brief A generic mouse movement.
 * \ingroup group_uinput
 */
typedef struct _input_mouse_t {
    int32_t dx;     /*!< \brief The change in movement along the x axis */
    int32_t dy;     /*!< \brief The change in movement along the y axis */
} input_mouse_t;

/*! \brief A generic touchscreen pointer descriptor. 
 * \ingroup group_uinput
 */
typedef enum _input_ts_type_e {
    INPUT_TS_FINGER,        /*!< \brief The touch was generated by a finger. */
    INPUT_TS_PEN,           /*!< \brief The touch was generated by a pen. */
} input_ts_type_e;

/*! \brief A generic touchscreen event. 
 * \ingroup group_uinput
 */
typedef struct _input_ts_t {
    input_ts_type_e type; /*!< \brief The type of stylus */
    uint32_t tracking_id; /*!< \brief The id assigned to each stylus */
     int32_t  location_x; /*!< \brief Distances from top left origin in x */
     int32_t  location_y; /*!< \brief Distance from top left origin in y */
    uint32_t    pressure; /*!< \brief An indication of the pressure used to generate the touch. */
    uint32_t major_width; /*!< \brief The presses major axis width */
    uint32_t minor_width; /*!< \brief The presses minor axis width */
    float    orientation; /*!< \brief A value in between [0, 1] which corresponds to [0, 2*pi] */
} input_ts_t;

/*! \brief A generic joystick event. 
 * \ingroup group_uinput
 */
typedef struct _input_joy_t {
    uint8_t  vx;          /*!< \brief Assume [0-255] Range, Fuzz=4, Flat=8 */
    uint8_t  vy;          /*!< \brief Assume [0-255] Range, Fuzz=4, Flat=8 */
} input_joy_t;

/*! \brief An input type list. 
 * \ingroup group_uinput
 */
typedef enum _input_type_t {
    INPUT_TYPE_KEY,         /*!< \brief A keyboard input event */
    INPUT_TYPE_MOUSE,       /*!< \brief A mouse input event */
    INPUT_TYPE_TOUCH,       /*!< \brief A touchscreen event */
    INPUT_TYPE_JOYSTICK,    /*!< \brief A joystick event */
    INPUT_TYPE_MAX,
} input_type_e;

/*! \brief A data structure which describes the input event. 
 * \ingroup group_uinput
 */
typedef struct _input_t {
    input_type_e type;      /*!< \brief The \ref input_type_e which indicates how to read the union */
    union {
        input_key_t     key;   /*!< \brief All 2-state keys should be pass here (keybd, mice, joy buttons) */
        input_mouse_t   mouse; /*!< \brief All relative mouse movements will be placed in here */
        input_ts_t      touch; /*!< \brief All touch events will be placed in here. */
        input_joy_t     joy;   /*!< \brief All joystick relative movements will be placed here. */
    } data;  /*!< \brief The union of all input type data */
} input_t;

#ifdef _UINPUT_FEATURE
#if defined(ANDROID) || defined(LINUX)
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/uinput.h>
#include <sys/time.h>
#include <unistd.h>

/*! \brief The user input device on Linux system wraps /dev/uinput.
 * \ingroup group_uinput
 */
typedef struct _uinput_t {
    struct uinput_user_dev uud;    /*!< \brief the user input user device structure */
    int                    ufile;  /*!< \brief the handle to the /dev/uinput driver */
} uinput_t;

#elif defined(WIN32) || defined(CYGWIN)

#include <windows.h>
/*! \brief The user input device on Windows hooks the Window of the process. 
 * \ingroup group_uinput
 */
typedef struct _uinput_t {
    HWND hWindow;               /**< We use the window hook to deliver events */
} uinput_t;

#elif defined(DARWIN)
#undef _UINPUT_T_FUNCS // no support yet for input on Mac
#elif defined(__QNX__)
#define _UINPUT_T_FUNCS // skeletal support
#include <screen/screen.h>
#include <sys/types.h>
#include <sys/keycodes.h>

/*! \brief On QNX systems, the user input events are routed through screen.
 * \ingroup group_uinput
 */
typedef struct _uinput_t {
    screen_context_t context;
    screen_display_t display;
} uinput_t;

#endif
#endif

#ifdef _UINPUT_T_FUNCS

#ifdef __cplusplus
extern "C" {
#endif

/*! \brief Opens the user input device. 
 * \param [in] dev_name The name of the device to open. 
 * \return Returns a handle to the user input device.
 * \retval NULL is returned when device could not be opened. 
 * \post \ref uinput_close
 * \ingroup group_uinput
 */
uinput_t *uinput_open(char *dev_name);

/*! \brief Sends an input event to the user input device. 
 * \param [in] u The handle to the user input device.
 * \param [in] i The input event to send.
 * \return Returns a bool_e.
 * \retval true_e if the event was sent
 * \retval false_e if the event was not sent.
 * \pre \ref uinput_open
 * \post \ref uinput_close after all events have been sent.
 * \ingroup group_uinput
 */
bool_e uinput_send(uinput_t *u, input_t *i);

/*! \brief Closes the user input device. 
 * \param [in] u The handle to the user input device. 
 * \return Returns a bool_e.
 * \retval true_e if the device was closed.
 * \retval false_e if the device was not closed or an error occurred.
 * \pre \ref uinput_open
 * \ingroup group_uinput
 */
bool_e uinput_close(uinput_t *u);

#ifdef __cplusplus
}
#endif

#endif // _UINPUT_T_FUNCS

#endif
